import logging
import eventlet
from flask import Flask,jsonify

#导入跨域对象
from ext import cors
#导入db对象
from ext import db
#导入cache
from ext import cache
#导入socketio
from ext import socketio
from ext import limiter
#导入拓展的配置内容
from ext.config import cache_config_redis,cache_config_mem,cors_config,get_remote_address

#导入中间件
from base.middleware import after_request  #响应前执行的中间件
from base.middleware import before_request #请求前执行的中间件

#导入配置字典
from base.settings import envs

#导入日志
from base.logger import getLogHandlerFile
from base.logger import getLogHanderTime

#定时任务
from base.scheduler import SchedulerManage

#注册socketio的命名空间
from apps.websocket.consumers import TotalWebsocketNamespace

#导入蓝图
from apps.user.urls import user_bp
from apps.html.urls import html_bp

def create_app():
    #创建一个flask实例，传递__name__ ,是把当前文路径作为flask实例的根路径
    #static和templates都是创建在该路径下的
    app = Flask(__name__,static_folder='../static',template_folder='../templates') #static目录位置是上层的static
    eventlet.monkey_patch()  # 开启补丁机制
    '基本配置'
    #导入配置从类中
    app.config.from_object(envs.get('default'))

    '日志配置'
    app.logger.addHandler(getLogHanderTime()) #基于时间
    app.logger.addHandler(getLogHandlerFile()) #基于文件大小
    app.logger.setLevel(logging.INFO)

    '中间件'
    #每次响应前都先设置好响应头，做好跨域
    app.after_request(after_request) #【1、使用中间件解决跨域】
    #执行请求处理前的中间件,
    app.before_request(before_request)

    '异常处理'
    @app.errorhandler(500)
    def handle_exception(e):
        # 将异常错误写到日志文件中
        app.logger.exception(str(e))
        # print(e, type(e))
        # 对异常错误的响应，使用api的格式
        return jsonify(code=500, message=str(e)), 500

    '拓展配置'
    #配置db对象 将db对象与app进行绑定，orm对象与app绑定
    db.init_app(app)
    #配置跨域，supports_credentials=True 允许携带cookies等信息
    cors.init_app(app,**cors_config) #【2、使用三方扩展解决跨域】
    #配置缓存
    cache.init_app(app=app,config=cache_config_redis)
    #配置socketio
    socketio.init_app(app,cors_allowed_origins='*')
    #配置流量控制
    limiter.init_app(app)

    'socketio注册命名空间的位置: 必须在这个py文件中注册'
    socketio.on_namespace(TotalWebsocketNamespace('/')) #使用默认的全局名称空间

    '蓝图注册'
    app.register_blueprint(user_bp)
    app.register_blueprint(html_bp)

    '定时任务'
    # SchedulerManage()

    return app
